/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.tests;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;
import mosdi.fa.Alphabet;
import mosdi.fa.GeneralizedString;
import mosdi.fa.GeneralizedStringsHammingNFA;
import mosdi.fa.GeneralizedStringsNFA;
import mosdi.fa.NFA;
import mosdi.util.BitArray;
import mosdi.util.Iupac;
import mosdi.util.iterators.AbelianPatternInstanceIterator;

public class GeneralizedStringsHammingNFATest extends TestCase {

	private static final int[] text = Alphabet.getDnaAlphabet().buildIndexArray("CACCAGCAATTGAATTAAGTCCCGAAGGAGAGAGATCGCTATATGGGCAGTGGGTGAGTCCCCCGCCCGCGCCGTCTATGCAGGTCATTGCCGCACTTCGCTTATTATCGTATTACTGTGAGTGATTAGATATTCTGGCCAGTTGTTGCTTACCTCTTGATTTAAATTGGCCTAGTCCCCTCATAATATCTTACCACCTCTTGACAGGTGTATTACTTCTAATTGTTTCGTAGCGATATGATTTTTCTTTGTAAAGACGTTTCACGCAGAAACTCACGCTTGCTTGGGAGGGTCAGTGTGGAGGAGACACTGTTTGAACGTCCCGCGCTGACAACCGTCGAGTTGAGAGGCCACGCGTAAGAGACTGGATTGACGAATAATCCAAGGCCTCCACGGTCGCGTCTTCTTACTGCAGTGGTGGGGCCGTCGTCCTACTTGGCGTTAGGAGAATTAAGCCATGCCGGAACGGCGCAGTAAATGTCCTGCCAGAACATTGGTGT");
	
	public static void assertMatching(int hammingDistance, int[] text, GeneralizedString... patterns) {
		// generate a list of disturbed patterns
		List<GeneralizedString> patternsWithErrors = new ArrayList<GeneralizedString>();
		for (GeneralizedString pattern : patterns) {
			patternsWithErrors.add(pattern);
			for (int k=1; k<=hammingDistance; ++k) {
				// iterate over all possible distributions of errors
				int[] frequencies = {pattern.length()-k, k};
				AbelianPatternInstanceIterator iterator = new AbelianPatternInstanceIterator(frequencies);
				while (iterator.hasNext()) {
					int[] errors = iterator.next();
					BitArray[] modifiedPattern = new BitArray[pattern.length()];
					boolean skip = false;
					for (int i=0; i<pattern.length(); ++i) {
						modifiedPattern[i] = new BitArray(pattern.getPosition(i));
						if (errors[i]==1) modifiedPattern[i].invert();
						if (modifiedPattern[i].allZero()) {
							skip = true;
							break;
						}
					}
					if (!skip) {
						patternsWithErrors.add(new GeneralizedString(pattern.getAlphabet(), modifiedPattern));
					}
				}
			}
		}
		NFA nfa0 = new GeneralizedStringsNFA(patternsWithErrors);
		NFA nfa1 = new GeneralizedStringsHammingNFA(Arrays.asList(patterns), hammingDistance);
		assertEquals(nfa0.countMatches(text), nfa1.countMatches(text));
	}
	
	public void testMatching() {
		assertMatching(0, text, Iupac.toGeneralizedString("ACBNTY"));
		assertMatching(1, text, Iupac.toGeneralizedString("ACBNTY"));
		assertMatching(2, text, Iupac.toGeneralizedString("ACBNTY"));
		assertMatching(2, text, Iupac.toGeneralizedString("ACBTNY"),Iupac.toGeneralizedString("ACBTNY"));
		assertMatching(3, text, Iupac.toGeneralizedString("ACBTNY"),Iupac.toGeneralizedString("ATTANYTT"));
	}
	
}
